#include "bsp_http.h"
#include "cJSON.h"
#include <sys/socket.h>

#define TAG "bsp_http"

typedef struct {
    char *data;
    size_t length;
} http_response_t;

static esp_err_t version_check_event_handler(esp_http_client_event_t *evt)
{
    http_response_t *response = (http_response_t *)evt->user_data;
    
    switch (evt->event_id) {
    case HTTP_EVENT_ON_DATA: {
        char *new_ptr = realloc(response->data, response->length + evt->data_len + 1);
        if (!new_ptr) {
            ESP_LOGE(TAG, "内存不足! 需要 %d 字节", response->length + evt->data_len + 1);
            return ESP_FAIL;
        }
        response->data = new_ptr;
        memcpy(response->data + response->length, evt->data, evt->data_len);
        response->length += evt->data_len;
        response->data[response->length] = '\0';
        break;
    }
    case HTTP_EVENT_ON_HEADER:
        if (strcasecmp(evt->header_key, "Content-Length") == 0) {
            ESP_LOGI(TAG, "Content-Length: %s", evt->header_value);
        }
        break;
    default:
        break;
    }
    return ESP_OK;
}

// 修改返回值类型为int
int check_firmware_version(char *ota_url)
{
    http_response_t response = {0};
    int server_version = -1;

    esp_http_client_config_t config = {
        .url = VERSION_CHECK_URL,
        .event_handler = version_check_event_handler,
        .user_data = &response,
        .buffer_size = HTTP_RESP_BUFFER_SIZE,
        .timeout_ms = 8000,
        .disable_auto_redirect = true
    };

    esp_http_client_handle_t client = esp_http_client_init(&config);
    if (!client) {
        ESP_LOGE(TAG, "HTTP客户端初始化失败");
        return -1;
    }

    esp_err_t ret = esp_http_client_perform(client);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "HTTP请求失败: %s", esp_err_to_name(ret));
        goto cleanup;
    }

    int status_code = esp_http_client_get_status_code(client);
    if (status_code != 200) {
        ESP_LOGE(TAG, "HTTP错误码: %d", status_code);
        goto cleanup;
    }

    if (response.length < 10 || response.data[0] != '{' || response.data[response.length-1] != '}') {
        ESP_LOGE(TAG, "无效JSON数据, 长度: %d", response.length);
        goto cleanup;
    }

    cJSON *root = cJSON_Parse(response.data);
    if (!root) {
        ESP_LOGE(TAG, "JSON解析失败! 原始数据:\n%.*s", 
                response.length < 128 ? response.length : 128, response.data);
        goto cleanup;
    }

    cJSON *code = cJSON_GetObjectItem(root, "code");
    cJSON *data = cJSON_GetObjectItem(root, "data");
    if (!cJSON_IsNumber(code) || code->valueint != 200 || !cJSON_IsObject(data)) {
        ESP_LOGE(TAG, "响应结构异常");
        cJSON_Delete(root);
        goto cleanup;
    }

    cJSON *server_ver = cJSON_GetObjectItem(data, "version");
    cJSON *download_url = cJSON_GetObjectItem(data, "url");
    if (!cJSON_IsNumber(server_ver) || !cJSON_IsString(download_url)) {
        ESP_LOGE(TAG, "数据格式错误");
        cJSON_Delete(root);
        goto cleanup;
    }
    
    if (server_ver->valueint > CURRENT_VERSION) {
        strlcpy(ota_url, download_url->valuestring, OTA_URL_SIZE);
        server_version = server_ver->valueint;
        ESP_LOGI(TAG, "发现新版本: %d → %d", CURRENT_VERSION, server_version);
    }
    else{
        server_version = server_ver->valueint;
        ESP_LOGI(TAG, "版本: CURRENT_VERSION:%d  server_version:%d", CURRENT_VERSION, server_version);
    }

    cJSON_Delete(root);

cleanup:
    if (response.data) free(response.data);
    esp_http_client_cleanup(client);
    return server_version;
}


esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
    switch (evt->event_id) {
    case HTTP_EVENT_ERROR:
        ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
        break;
    case HTTP_EVENT_ON_CONNECTED:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
        break;
    case HTTP_EVENT_HEADER_SENT:
        ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
        break;
    case HTTP_EVENT_ON_HEADER:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
        break;
    case HTTP_EVENT_ON_DATA:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
        break;
    case HTTP_EVENT_ON_FINISH:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
        break;
    case HTTP_EVENT_DISCONNECTED:
        ESP_LOGD(TAG, "HTTP_EVENT_DISCONNECTED");
        break;
    case HTTP_EVENT_REDIRECT:
        ESP_LOGD(TAG, "HTTP_EVENT_REDIRECT");
        break;
    }
    return ESP_OK;
}

/* 修改后的OTA任务函数 */
void simple_ota_example_task(void *pvParameter)
{



    char ota_url[OTA_URL_SIZE] = {0};
    int server_version = -1;
    while(1)
    {
        server_version = check_firmware_version(ota_url);
        if(server_version != -1)
        {
            break;
        }
        vTaskDelay(2000);
    }
   
    
    if (server_version <= CURRENT_VERSION) {
        ESP_LOGI(TAG, "No update needed");
        vTaskDelete(NULL);
        return;
    }

    ESP_LOGI(TAG, "Starting OTA update from URL: %s", ota_url);
    
    // 第二步：配置OTA参数
    esp_http_client_config_t config = {
        .url = ota_url,
        .crt_bundle_attach = esp_crt_bundle_attach,
        .event_handler = _http_event_handler,
        .keep_alive_enable = true,
    };

    esp_https_ota_config_t ota_config = {
        .http_config = &config,
    };

    // 执行OTA升级
    esp_err_t ret = esp_https_ota(&ota_config);
    if (ret == ESP_OK) {
        ESP_LOGI(TAG, "OTA Success, Rebooting...");
        esp_restart();
    } else {
        ESP_LOGE(TAG, "OTA Failed! Error: %s", esp_err_to_name(ret));
    }
    // 启动TCP客户端任务
    if (gs_wificonfig.handle.tcp_task_handle == NULL) {
        xTaskCreate(tcp_client_task, "tcp_client", 4096, NULL, configMAX_PRIORITIES - 1, &gs_wificonfig.handle.tcp_task_handle);
    }
    ESP_LOGI(TAG, "线程终止");
    vTaskDelete(NULL);
    
}




static void print_sha256(const uint8_t *image_hash, const char *label)
{
    char hash_print[HASH_LEN * 2 + 1];
    hash_print[HASH_LEN * 2] = 0;
    for (int i = 0; i < HASH_LEN; ++i) {
        sprintf(&hash_print[i * 2], "%02x", image_hash[i]);
    }
    ESP_LOGI(TAG, "%s %s", label, hash_print);
}

static void get_sha256_of_partitions(void)
{
    uint8_t sha_256[HASH_LEN] = { 0 };
    esp_partition_t partition;

    // get sha256 digest for bootloader
    partition.address   = ESP_BOOTLOADER_OFFSET;
    partition.size      = ESP_PARTITION_TABLE_OFFSET;
    partition.type      = ESP_PARTITION_TYPE_APP;
    esp_partition_get_sha256(&partition, sha_256);
    print_sha256(sha_256, "SHA-256 for bootloader: ");

    // get sha256 digest for running partition
    esp_partition_get_sha256(esp_ota_get_running_partition(), sha_256);
    print_sha256(sha_256, "SHA-256 for current firmware: ");
}


void Http_Ota_Net_Init()
{
    get_sha256_of_partitions();
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    xTaskCreate(simple_ota_example_task, "ota_example_task", 8192, NULL, 5, NULL);
}

void Http_Ota_Init()
{
    get_sha256_of_partitions();
    xTaskCreate(simple_ota_example_task, "ota_example_task", 8192, NULL, 5, NULL);
}
